﻿//  Copyright (c) 2009 Ray Liang (http://www.dotnetage.com)
//  Dual licensed under the MIT and GPL licenses:
//  http://www.opensource.org/licenses/mit-license.php
//  http://www.gnu.org/licenses/gpl.html
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.IO;
using System.Web;
namespace DNA.Mvc.jQuery
{
    /// <summary>
    /// Enables declarative access to XML data for Hierarchical data controls.
    /// </summary>
    public class XmlNodeProvider : HierarchicalNodeProviderBase
    {
        private string _xmlFileUrl = "";
        private XmlDocument document;
        private HierarchicalNode root;

        public string Path { get; set; }

        /// <summary>
        /// Gets/Sets the xml file url
        /// </summary>
        public string FileUrl
        {
            get { return _xmlFileUrl; }
            set { _xmlFileUrl = value; }
        }
        
        /// <summary>
        /// Initialize the XmlNodeProvider
        /// </summary>
        public XmlNodeProvider() { }

        /// <summary>
        /// Initialize the XmlNodeProvider by specified the xml file url
        /// </summary>
        /// <param name="xmlFileUrl">The xml file url</param>
        public XmlNodeProvider(string xmlFileUrl)
        {
            document = new XmlDocument();
            document.Load(xmlFileUrl);
            nodeDataBound = MapNodeInternal;
        }

        public XmlNodeProvider(string xmlFile, MapAction<XmlNode,HierarchicalNode> databound)
            : this(xmlFile)
        {
            nodeDataBound = databound;
        }

        private MapAction<XmlNode, HierarchicalNode> nodeDataBound;

        public MapAction<XmlNode, HierarchicalNode> NodeDataBound
        {
            get { return nodeDataBound; }
            set { nodeDataBound = value; }
        }

        /// <summary>
        /// Receives the child nodes of the specified node.
        /// </summary>
        /// <param name="node">Specified the node instance.</param>
        /// <returns>A collection of the child nodes,.</returns>
        public override IEnumerable<HierarchicalNode> GetChildNodes(HierarchicalNode node)
        {
            if (node.Item != null)
            {
                var element = (XmlNode)node.Item;
                if (element.HasChildNodes)
                {
                    var nodes = new List<HierarchicalNode>();
                    //var _child=element.ChildNodes;
                    //foreach (var e in _child)
                    for (int i = 0; i < element.ChildNodes.Count;i++ )
                    {
                        var childNode = new HierarchicalNode(this);
                        var _state = nodeDataBound.Invoke( element.ChildNodes[i],childNode);
                        if (!_state) continue;

                        nodes.Add(childNode);
                        //nodes.Add(PopulateNodeFromElement(e));
                    }
                    return nodes;
                }
            }
            return null;
        }

        /// <summary>
        /// Receives the parent node by the specified node.
        /// </summary>
        /// <param name="node">Specified the node instance.</param>
        /// <returns>The parent node instance.The null value will be return when the parent not found.</returns>
        public override HierarchicalNode GetParentNode(HierarchicalNode node)
        {
            if (node.Item != null)
            {
                var element = (XmlNode)node.Item;
                if (element.ParentNode != null)
                {
                    var _parent = new HierarchicalNode(this as IHierarchicalNodeProvider);
                    if (nodeDataBound.Invoke(element.ParentNode,_parent ))
                        return _parent;
                    else
                        return null;
                        //return PopulateNodeFromElement(element.Parent);
                }
            }
            return null;
        }

        /// <summary>
        /// Add the children node to the specified node.
        /// </summary>
        /// <param name="parentNode">Specified the parent node to add the children.</param>
        /// <param name="node">Specified the child node to add.</param>
        public override void AddChildren(HierarchicalNode parentNode, HierarchicalNode node)
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Remove the specified node.
        /// </summary>
        /// <param name="node">The node to remove.</param>
        public override void RemoveNode(HierarchicalNode node)
        {
            throw new NotImplementedException();
        }

        private bool MapNodeInternal( XmlNode xmlNode,HierarchicalNode node)
        {
            //var attrs = xmlNode.Attributes;
            if (!string.IsNullOrEmpty(xmlNode.Value))
                node.Title = xmlNode.Value;

            //foreach (var attr in attrs)
            for (int i = 0; i < xmlNode.Attributes.Count;i++ )
            {
                //attrs.Item()
                var attr = xmlNode.Attributes[i];
                if (attr.LocalName.Equals("Title", StringComparison.OrdinalIgnoreCase))
                {
                    if (string.IsNullOrEmpty(node.Title))
                        node.Title = attr.Value;
                    continue;
                }

                if (attr.LocalName.Equals("Target", StringComparison.OrdinalIgnoreCase)) { node.Target = attr.Value; continue; }
                if (attr.LocalName.Equals("Description", StringComparison.OrdinalIgnoreCase)) { node.Description = attr.Value; continue; }
                if (attr.LocalName.Equals("ResourceKey", StringComparison.OrdinalIgnoreCase)) { node.ResourceKey = attr.Value; continue; }

                if (attr.LocalName.Equals("NavigateUrl", StringComparison.OrdinalIgnoreCase))
                {
                    node.NavigateUrl = attr.Value;
                    if (VirtualPathUtility.IsAppRelative(node.NavigateUrl))
                        node.NavigateUrl = VirtualPathUtility.ToAbsolute(node.NavigateUrl);
                    continue;
                }

                if (attr.LocalName.Equals("ImageUrl", StringComparison.OrdinalIgnoreCase))
                {
                    node.ImageUrl = attr.Value;
                    if (VirtualPathUtility.IsAppRelative(node.ImageUrl))
                        node.ImageUrl = VirtualPathUtility.ToAbsolute(node.ImageUrl);
                    continue;
                }

                if (attr.LocalName.Equals("Key", StringComparison.OrdinalIgnoreCase)) { node.Key = attr.Value; continue; }
                node.Attributes.Add(attr.LocalName, attr.Value);
            }

            if ((!string.IsNullOrEmpty(g_target)) && (string.IsNullOrEmpty(node.Target)))
                node.Target = g_target;

            if ((!string.IsNullOrEmpty(g_imgUrl)) && (string.IsNullOrEmpty(node.ImageUrl)))
                node.ImageUrl = g_imgUrl;

            node.Item =xmlNode;
            return true;
        }

        /// <summary>
        /// Receives the root node.
        /// </summary>
        public override HierarchicalNode RootNode
        {
            get
            {
                if (root == null)
                {
                    root = new HierarchicalNode(this);
                    XmlNode rootNode = null;
                    //var rootNode =document.FirstChild;// document.DocumentElement;
                   //document.d
                    if (!string.IsNullOrEmpty(Path))
                        rootNode = document.SelectSingleNode(Path);
                    else
                        rootNode = document.SelectSingleNode("/node");
                    if (rootNode.Attributes["target"] != null)
                        g_target = rootNode.Attributes["target"].Value;
                    if (rootNode.Attributes["imageUrl"] != null)
                        g_imgUrl = rootNode.Attributes["imageUrl"].Value;

                    nodeDataBound.Invoke(rootNode,root);
                }
                    return root;
            }
            set
            { }
        }
        private string g_target = "_self";
        private string g_imgUrl = "";

        /// <summary>
        /// Find the node instance by specified the node key.
        /// </summary>
        /// <param name="key">The key value of the node.</param>
        /// <returns>If the node not found the null value will be return.</returns>
        public override HierarchicalNode FindNodeFormKey(string key)
        {
            //var element = (from e in document.Descendants()
            //              where e.Attribute("Key").Value.Equals(key, StringComparison.OrdinalIgnoreCase)
            //              select e).FirstOrDefault();
            var element = document.SelectSingleNode(key);
            if (element != null)
            {
                var n = new HierarchicalNode(this as IHierarchicalNodeProvider);
                if (nodeDataBound.Invoke(element,n))
                    return n;
                else
                    return null;
                //return PopulateNodeFromElement(element);
            }
            return null;
        }
    }
}
